﻿using System;
using System.Collections.Generic;
using System.Linq;
using LiteBlog.Common.Entities;
using LiteBlog.Components.Contracts;
using LiteBlog.Components.Enums;
using LiteBlog.Repositories.Contracts;
using LiteBlog.Common.Components;

namespace LiteBlog.Components
{
    public class PageComp : BaseComp<IPageRepository>, IPageComp
    {
        private ISiteMapComp _sitemapComp;
        public ISiteMapComp SiteMapComponent
        {
            get
            {
                return _sitemapComp;
            }
        }

        public PageComp(IPageRepository data, ICacheComp cache, ISiteMapComp sitemapComp) : base(data, cache)
        {
            _sitemapComp = sitemapComp;
        }

        public IEnumerable<Page> Get()
        {
            var pages = _cache.Get<List<Page>>(CacheType.Pages);
            if (pages == null)
            {
                pages = _data.GetPages();
                _cache.Put(CacheType.Pages, pages);
            }
            return pages;
        }

        public List<Page> GetPublished()
        {
            return Get().Where(p => p.Published).ToList();
        }

        public List<Page> GetPagesInHeaderMenu()
        {
            return Get().Where(p => p.IncludeInHeaderMenu).ToList();
        }

        public Page Get(string id)
        {
            var page = Get().SingleOrDefault(p => p.FileId == id);
            if (page != null)
            {
                page = _data.Load(id);
            }   
            return page;
        }

        public Page GetPublished(string id)
        {
            var page = Get().SingleOrDefault(p => p.Published && (p.FileId == id));
            if (page != null)
            {
                page = _cache.GetPage(id);
                if (page == null)
                {
                    page = _data.Load(id);
                    _cache.PutPage(id, page);
                }
            }
            return page;
        }

        public MethodResult Create(Page item)
        {
           _data.Save(item);
            return MethodResult.CreateSuccess;
        }

        public MethodResult Update(string olid, Page item)
        {
            var oldItem = Get(olid);
            if (oldItem.FileId != item.FileId)
            {
                if (Get(item.FileId) != null)
                    return MethodResult.DuplicateId;

                item.Body = oldItem.Body;
                item.Published = oldItem.Published;
                item.IncludeInHeaderMenu = oldItem.IncludeInHeaderMenu;

                _data.Delete(oldItem.FileId);
                _data.Save(item);
                SiteMapComponent.UpdateUrl(SiteMapType.Page, GetSiteMapUrl(olid).Location, GetSiteMapUrl(item.FileId).Location);
            }
            else
            {
                oldItem.Title = item.Title;
                _data.Save(oldItem);
                SiteMapComponent.Update(SiteMapType.Page, GetSiteMapUrl(oldItem.FileId));
            }
            return MethodResult.UpdateSuccess;
        }

        public MethodResult Delete(string id)
        {
            _data.Delete(id);
            SiteMapComponent.Delete(SiteMapType.Page, GetSiteMapUrl(id).Location);
            return MethodResult.DeleteSuccess;
        }

        public MethodResult Publish(Page page)
        {
            string oldFileId = page.FileId;
            Delete(oldFileId);

            string newFileId = page.Title.Replace(" ", "");
            page.FileId = CreateUniqueId(newFileId);
            page.Published = true;
            Create(page);
            SiteMapComponent.Add(SiteMapType.Page, GetSiteMapUrl(newFileId));
            return MethodResult.PublishSuccess;
        }

        public MethodResult Unpublish(string id)
        {
            var page = Get(id);
            page.Published = false;
            Save(page);
            SiteMapComponent.Delete(SiteMapType.Page, GetSiteMapUrl(id).Location);
            return MethodResult.UnpublishSuccess;
        }

        private void Save(Page page)
        {
            Create(page);
        }

        private string CreateUniqueId(string fileId)
        {
            if (_data.IsUniqueId(fileId))
                return fileId;

            int uid = 1;
            string uniqueId = fileId + "-" + uid.ToString();
            while (_data.IsUniqueId(uniqueId))
            {
                ++uid;
                uniqueId = fileId + "-" + uid.ToString();
            }
            return uniqueId;
        }

        private SiteMapUrl GetSiteMapUrl(string fileId)
        {
            var siteMapUrl = new SiteMapUrl
            {
                Location = "/Page/" + fileId,
                LastModifiedTime = DateTime.UtcNow,
                Priority = 1.0F
            };
            return siteMapUrl;
        }
    }
}